<?php
namespace logic\sys;
class WebUploader{
    
    private $session_key = 'logic_sys_webuploader';
    
    /**
     * 上传文件
     */
    public function uploadFile(){
        if( $_REQUEST['chunks'] ){
            return $this->chunkedUpload();
        }else{
            $Upload = new \logic\sys\Upload();            
            $result = $Upload->images($_REQUEST['filetype']);
            $result['status'] = $result['ret'] ? 'success' : 'error';
            return $result;
        }
    }
    
    
    /**
     * 分块上传处理
     */
    private function chunkedUpload(){      
        
        $param = $_REQUEST;
        $file  = $_FILES['file'];
        
        try{            
            $tempPath = $this->getTempPath();
            $name = $this->buildSaveName($tempPath,date('YmdHis'));
            $tempFile = $tempPath.$name;
            
            if (!move_uploaded_file($file['tmp_name'], $tempFile)) {
                // 文件移动失败
                return false;
            }else{
                $fileKey = $param['fileid'].$param['size']; 
                $chunkedCasch = session($this->session_key.$fileKey);
                $param['fileid'] = $param['fileid'] ?: $param['id'];            
                $tempList = [
                    'file'      => $tempFile,
                    'chunks'    => $param['chunks'],
                    'chunk'     => $param['chunk'],
                    'size'      => $param['size'],
                    'name'      => $param['name'],
                    'ext'       => pathinfo($file['name'], PATHINFO_EXTENSION),
                    'filetype'  => $param['filetype']
                ];
                $chunkedCasch[$tempList['chunk']] = $tempList;
                session($this->session_key.$fileKey,$chunkedCasch);
                if( count($chunkedCasch) == $tempList['chunks']){
                    return $this->merge($fileKey);
                }
                
                $return = [
                    'ret'       => false,
                    'status'    => 'uploading',
                    'filekey'   => $fileKey
                ];
                return $return;
            }
            
        }catch( \think\Exception $e){
            $return = [
                'ret'       => false,
                'status'    => 'error',
                'error'     => $e->getMessage()
            ];
        }
        return $return;
        
    }    
    
    /**
     * 合并成一个文件
     */
    public function merge($fileKey){
        try{
            $thisFile = session($this->session_key.$fileKey);
            if( !$thisFile ){
                $cacsh =  session($this->session_key.$fileKey.'file');
                if($cacsh ) return $cacsh;
                logicE('文件不存在');
            }  
            ksort($thisFile);  
                               
            if( count($thisFile) != $thisFile[0]['chunks'] ) logicE('文件上传失败[缺失]');
            
            $filetype = $thisFile[0]['filetype'] ?: 'apk';
            $ext      = $thisFile[0]['ext'] ?: 'apk';
            $filename = $thisFile[0]['name'];
            $size     = $thisFile[0]['size'];
            
            $savePath = $this->getSavePath($filetype);
            $saveName = $this->buildSaveName($savePath,'', $ext );
            $saveFile = $savePath.$saveName; 
            
            $out = @fopen($saveFile, "wb");
            if( !$out ) logicE('保存文件失败');        
            foreach( $thisFile as $key => $val ){
                $in = @fopen($val['file'], "rb");
                if(!$in)  logicE('文件上传失败');
                while ($buff = fread($in, 4096)) {
                    fwrite($out, $buff);
                }            
                @fclose($in);
                unlink( $val['file']);
            }
            @fclose($out);
            
            $file = DIRECTORY_SEPARATOR.'uploads'.explode('\public\uploads',$saveFile)[1];
            $md5 = md5( file_get_contents($saveFile));
            $result = [
                'ret'      => true,
                'md5'      => $md5,
                'status'   => 'success',
                'filehttp' => Config('url.url.m').$file,
                'filedir'  => '.'.$file,
                'filename' => $filename,
                'size'     => $size,
            ];
            session($this->session_key.$fileKey.'file',$result);
            session($this->session_key.$fileKey,null);
            
        }catch( \think\Exception $e){
            $result = [
                'ret'      => false,
                'status'   => 'error',
                'error'    => $e->getMessage()                
            ];
        }
        return $result;
    }
    
    /**
     * 创建一个唯一名称
     */
    private function buildSaveName($path,$preStr = '', $ext = 'temp' ){
        $randStr = \core\helper\Tools::rand(12,3);
        $saveName = $preStr.$randStr.'.'.$ext;
        if( file_exists( $path.$saveName ) ){
            return $this->buildSaveName($path,$preStr,$ext,true);
        }
        return $saveName;
    }
    
    /**
     * 获取保存文件的目录
     */
    private function getSavePath($type = ''){
        if( !$type ) $type = 'default';
        $type = trim($type,DIRECTORY_SEPARATOR) .DIRECTORY_SEPARATOR;
        $saveFath = \think\facade\Env::get('ROOT_PATH').'public'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
        //$main = 'home'.DIRECTORY_SEPARATOR;
        $dataPath = date('Y').DIRECTORY_SEPARATOR.date('m').DIRECTORY_SEPARATOR.date('d').DIRECTORY_SEPARATOR;
        $saveFath = $saveFath.$type.$dataPath;
        $this->checkPath($saveFath);
        return $saveFath;
    }
    
    /**
     * 获取一个临时的保存目录
     */
    private function getTempPath(){
        $saveFath = \think\facade\Env::get('ROOT_PATH').'public'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'temp'.DIRECTORY_SEPARATOR;
        $this->checkPath($saveFath);
        return $saveFath;
    }
    
    /**
     * 判断保存目录是否存在 否则则创建
     */
    private function checkPath($path){
        if (is_dir($path))  return true;
        if (mkdir($path, 0755, true))  return true;
        logicE($path.'目录创建失败');
    }
}